﻿using System.Collections.Generic;
using System.Reflection;
using smp.QueryDb.Structure;

namespace smp.QueryDb
{
    public interface IQueryMapTo<TViewModel>
    {
        Query<TViewModel> To(Column column);

        Query<TViewModel> ToNested<TNestedModel>(NestedMap<TNestedModel> nestedMap);
    }

    internal class QueryMapTo<TViewModel> : IQueryMapTo<TViewModel>
    {
        private readonly Query<TViewModel> _query;
        private readonly PropertyInfo _property;

        internal QueryMapTo(Query<TViewModel> query, PropertyInfo property)
        {
            _query = query;
            _property = property;
        }

        public Query<TViewModel> To(Column column)
        {
            _query.Structure.AddMap(_property, column);
            return _query;
        }

        public Query<TViewModel> ToNested<TNestedModel>(NestedMap<TNestedModel> nestedMap)
        {
            if (Helper.IsCollection(_property))
            {
                throw Helper.Error("Property {0} on entity {1} is invalid for mapping, nested collections are not supported as bad practice.",
                    _property.Name,
                    typeof(TViewModel).Name);
            }
            _query.Structure.AddNestedMap(_property, nestedMap.Maps);
            return _query;
        }
    }



    public interface IQueryMapAllTo<TViewModel>
    {
        Query<TViewModel> To(Table table);
    }

    internal class QueryMapAllTo<TViewModel> : IQueryMapAllTo<TViewModel>
    {
        private readonly Query<TViewModel> _query;
        private readonly List<PropertyInfo> _properties;

        internal QueryMapAllTo(Query<TViewModel> query)
        {
            _query = query;
            _properties = new List<PropertyInfo>();
            foreach(var property in typeof(TViewModel).GetProperties())
            {
                if (!property.PropertyType.IsValueType && property.PropertyType != typeof(string))
                    continue;
                _properties.Add(property);
            }
        }
        
        #region Implementation of IQueryMapAllTo<TViewModel>

        public Query<TViewModel> To(Table table)
        {
            var idProperty = _properties.Find(x => x.Name == table.Id.Name);
            if(idProperty != null)
            {
                _query.Structure.AddMap(idProperty, table.Id);
            }
            foreach(var column in table.Columns)
            {
                var columnProperty = _properties.Find(x => x.Name == column.Name);
                if(columnProperty != null)
                {
                    _query.Structure.AddMap(columnProperty, column);
                }
            }
            return _query;
        }

        #endregion
    }
}
